/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tonyodev.fetchapp.ability;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.utils.Color;
import ohos.bundle.IBundleManager;
import ohos.utils.Sequenceable;
import ohos.utils.net.Uri;

import com.tonyodev.fetch2.Download;
import com.tonyodev.fetch2.Error;
import com.tonyodev.fetch2.Fetch;
import com.tonyodev.fetch2.Request;
import com.tonyodev.fetch2.Status;
import com.tonyodev.fetch2core.Extras;
import com.tonyodev.fetch2core.FetchObserver;
import com.tonyodev.fetch2core.Func;
import com.tonyodev.fetch2core.MutableExtras;
import com.tonyodev.fetch2core.Reason;
import com.tonyodev.fetchapp.Data;
import com.tonyodev.fetchapp.ResourceTable;
import com.tonyodev.fetchapp.Utils;
import com.tonyodev.fetchapp.snackbar.SnackBar;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

import timber.log.Timber;

import static ohos.security.SystemPermission.WRITE_USER_STORAGE;

public class SingleDownloadAbility extends Ability implements FetchObserver<Download>, SnackBar.OnMessageClickListener {
    private static final int STORAGE_PERMISSION_CODE = 100;


    private Component mainView;
    private Text mTitleTextView;
    private Text mProgressTextView;
    private Text mEtaTextView;
    private Text mDownloadSpeedTextView;
    private Fetch fetch;
    private Request request;
    private SnackBar mSnackBar;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        getWindow().setStatusBarColor(Color.getIntColor("#303f9f"));
        super.setUIContent(ResourceTable.Layout_ability_single_download);

        initView();
    }

    private void initView() {
        mainView = findComponentById(ResourceTable.Id_ability_single_download);
        mTitleTextView = (Text) findComponentById(ResourceTable.Id_titleTextView);
        mProgressTextView = (Text) findComponentById(ResourceTable.Id_progressTextView);
        mEtaTextView = (Text) findComponentById(ResourceTable.Id_etaTextView);
        mDownloadSpeedTextView = (Text) findComponentById(ResourceTable.Id_downloadSpeedTextView);
        fetch = Fetch.Impl.getDefaultInstance();
        checkStoragePermission();
    }

    private void checkStoragePermission() {
        // 权限申请
        List<String> permissionsToRequest = new ArrayList<>();
        String[] permissions = new String[]{WRITE_USER_STORAGE};
        for (String permission : permissions) {
            if (verifyCallingPermission(permission) != IBundleManager.PERMISSION_GRANTED) {
                // 应用未被授予权限
                if (canRequestPermission(permission)) { // 是否可以申请弹框授权 如果可以就把权限添加到列表中
                    permissionsToRequest.add(permission);
                }
            }
        }

        if (!permissionsToRequest.isEmpty()) { //
            requestPermissionsFromUser(permissions, STORAGE_PERMISSION_CODE); // 说明有权限没有申请
        } else {
            enqueueDownload();
        }
    }

    private void enqueueDownload() {
        final String url = Data.sampleUrls[0];
        final String filePath = Data.getSaveDir(this) + "/movies/" + Data.getNameFromUrl(url);
        request = new Request(url, filePath);
        request.setExtras(getExtrasForRequest(request));

        fetch.attachFetchObserversForDownload(request.getId(), this)
            .enqueue(request, new Func<Request>() {
                @Override
                public void call(@NotNull Request result) {
                    request = result;
                }
            }, new Func<Error>() {
                @Override
                public void call(@NotNull Error result) {
                    Timber.d("SingleDownloadActivity Error: %1$s", result.toString());
                }
            });
    }

    @Override
    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults);
        if (requestCode == STORAGE_PERMISSION_CODE) {
            enqueueDownload();
        } else {
            new SnackBar.Builder(SingleDownloadAbility.this, mainView)
                .withMessage(getString(ResourceTable.String_permission_not_enabled))
                .show();
        }
    }

    private Extras getExtrasForRequest(Request request) {

        final MutableExtras extras = new MutableExtras();
        extras.putBoolean("testBoolean", true);
        extras.putString("testString", "test");
        extras.putFloat("testFloat", Float.MIN_VALUE);
        extras.putDouble("testDouble", Double.MIN_VALUE);
        extras.putInt("testInt", Integer.MAX_VALUE);
        extras.putLong("testLong", Long.MAX_VALUE);
        return extras;

    }

    @Override
    protected void onActive() {
        super.onActive();
        if (request != null) {
            fetch.attachFetchObserversForDownload(request.getId(), this);
        }
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        if (request != null) {
            fetch.removeFetchObserversForDownload(request.getId(), this);
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        fetch.close();
    }

    @Override
    public void onChanged(Download data, Reason reason) {
        updateViews(data, reason);
    }

    private void updateViews(Download download, Reason reason) {
        if (request.getId() == download.getId()) {
            if (reason == Reason.DOWNLOAD_QUEUED || reason == Reason.DOWNLOAD_COMPLETED) {
                setTitleView(download.getFile());
            }
            setProgressView(download.getStatus(), download.getProgress());
            mEtaTextView.setText(Utils.getETAString(this, download.getEtaInMilliSeconds()));
            mDownloadSpeedTextView.setText(Utils.getDownloadSpeedString(this, download.getDownloadedBytesPerSecond()));
            if (download.getError() != Error.NONE) {
                showDownloadErrorSnackBar(download.getError());
            }
        }

    }

    private void setProgressView(Status status, int progress) {
        switch (status) {
            case QUEUED: {
                mProgressTextView.setText(ResourceTable.String_queued);
                break;
            }
            case ADDED: {
                mProgressTextView.setText(ResourceTable.String_added);
                break;
            }
            case DOWNLOADING:
            case COMPLETED: {
                if (progress == -1) {
                    mProgressTextView.setText(ResourceTable.String_downloading);
                } else {
                    final String progressString = getString(ResourceTable.String_percent_progress, progress);
                    mProgressTextView.setText(progressString);
                }
                break;
            }
            default: {
                mProgressTextView.setText(ResourceTable.String_status_unknown);
                break;
            }
        }
    }

    private void setTitleView(String fileName) {
        final Uri uri = Uri.parse(fileName);
        mTitleTextView.setText(uri.getLastPath());

    }

    private void showDownloadErrorSnackBar(@NotNull Error error) {
        mSnackBar = new SnackBar.Builder(SingleDownloadAbility.this, mainView)
            .withOnClickListener(this)
            .withMessage("Download Failed: ErrorCode" + error)
            .withActionMessage("RETRY")
            .show();
    }

    @Override
    public void onMessageClick(Sequenceable token) {
        fetch.retry(request.getId());
        if (mSnackBar != null) {
            mSnackBar.hide();
        }

    }
}